package com.example.concurrentprogramming8016.synchronizedLearn;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.layouters.CurrentLayouter;
import org.openjdk.jol.layouters.Layouter;

import java.sql.Time;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @author liyanhao
 * @Date 2023-01-04 18:18
 * 偏向锁测试
 * non-biasable 无锁且不可偏向
 * biasable 无锁可偏向
 * biased 偏向锁
 * thin lock 轻量级锁
 * fat lock 重量级锁
 */
@Slf4j
public class LockEscalationDemo {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        //无锁
//        extracted(object);
        //偏向锁
        //JDK默认开启偏向锁，但延时的，
        // 需要通过参数-XX:BiasedLockingStartupDelay=0禁用延时。（idea在VM Options设置就行了）
        extracted1(object);
        //轻量级锁 添加获取hashcode方法的代码 偏向锁会升级到轻量级锁
        //偏向锁状态执行obj.notify() 会升级为轻量级锁，
//        extracted2(object);
        //调用obj.wait(timeout) 会升级为重量级锁
//        extracted3(object);

        //模拟两个线程轻微竞争场景 偏向锁升级为轻量级锁
//        extracted4(object);
        //两个线程没有时间延迟 锁会直接膨胀为重量级锁
//        extracted5(object);
        // 批量重偏向 机制：一个线程创建了大量对象并执行了初始化的同步操作，后来另一个线程也来将这些对象作为锁对象进行操作，这样导致大量的偏向锁撤销操作
        //批量撤销机制 在明显多线程竞争剧烈的场景下使用偏向锁是不合适的
        // 测试批量重偏向
        //延时产生可偏向的对象
//        extracted6(object);
    }

    private static void extracted6(Object object) throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        //创建一个list 来存放锁对象
        ArrayList<Object> list = new ArrayList<>();
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                Object o = new Object();
                synchronized (o) {
                    list.add(o);
                }
            }
            //防止线程复用 创建完成后 保持线程的存货状态
            try {
                TimeUnit.SECONDS.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }, "thread-1").start();
        //睡眠保证对象创建完成
        TimeUnit.SECONDS.sleep(3);
        System.out.println("打印thread-1 第二十个对象头信息:");
        System.out.println(ClassLayout.parseInstance(list.get(19)).toPrintable());

        //线程 2
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                Object o = list.get(i);
                synchronized (o) {
                    if (i > 15 && i <= 21 || i >= 38) {
                        System.out.println("thread-2打印第" + (i + 1) + "次 加锁执行中\t"
                                + ClassLayout.parseInstance(object).toPrintable());
                    }
                }
                if (i == 17 || i == 19) {
                    System.out.println("thread-2打印第" + (i + 1) + "次 释放执行中\t"
                            + ClassLayout.parseInstance(object).toPrintable());
                }
            }
            try {
                TimeUnit.SECONDS.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "thread-2").start();
        LockSupport.park();
    }

    private static void extracted5(Object object) throws InterruptedException {
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":");
                System.out.println();
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        }, "thread 1").start();
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":");
                System.out.println();
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        }, "thread 2").start();
    }

    private static void extracted4(Object object) throws InterruptedException {
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":");
                System.out.println();
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        }, "thread 1").start();
        //控制线程竞争的时机 不加这个会直接升级为重量级锁
        TimeUnit.SECONDS.sleep(10);
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":");
                System.out.println();
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        }, "thread 2").start();
    }

    private static void extracted3(Object object) {
        new Thread(() -> {
            synchronized (object) {
                try {
                    object.wait(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log.debug(ClassLayout.parseInstance(object).toPrintable());
            }
        }).start();
    }

    private static void extracted2(Object object) throws InterruptedException {
        new Thread(() -> {
            synchronized (object) {
                object.notify();
//                    object.wait(100);
                log.debug(ClassLayout.parseInstance(object).toPrintable());
            }
        }).start();
        Thread.sleep(10);
        System.out.println(ClassLayout.parseInstance(object).toPrintable());
    }

    private static void extracted1(Object object) {
        new Thread(() -> {
            synchronized (object) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log.debug(ClassLayout.parseInstance(object).toPrintable());
            }
        }).start();
    }

    private static void extracted(Object object) throws InterruptedException {
        log.debug(ClassLayout.parseInstance(object).toPrintable());
        Thread.sleep(1000);
        log.debug(ClassLayout.parseInstance(object).toPrintable());
    }


    private static void extracted() {
        //        log.debug(ClassLayout.parseInstance(new Object(), new CurrentLayouter()).toPrintable());
//        Thread.sleep(1000);
//        log.debug(ClassLayout.parseInstance(new Object()).toPrintable());
        Object obj = new Object();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "开始执行....\n" + ClassLayout.parseInstance(obj).toPrintable());
            synchronized (obj) {
                //直接加锁 生成一个偏向锁
                // 在锁中调用hashcode会升级为重量级锁
               /*
                obj.hashCode();
                try {
                    //重量级锁
                    obj.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                */
                System.out.println(Thread.currentThread().getName() + "获取锁执行中...\n"
                        + ClassLayout.parseInstance(obj).toPrintable());
            }
            System.out.println(Thread.currentThread().getName() + "释放锁...\n" + ClassLayout.parseInstance(obj).toPrintable());
        }, "thread1").start();
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());
    }
}
